perm filename EFSPKT.C[11,HE] blob sn#688192 filedate 1982-12-06 generic text, type T, neo UTF8
/* LINTLIBRARY */
/*
 * efsendpckt..c
 *
 * EFTP Package
 *
 *		THIS ASSUMES NOTHING ABOUT BYTE ORDER.
 * EfSendPckt -- send the next packet of an Eftp transfer
 *
 * Jeffrey Mogul @ Stanford	28-January-1981
 */

#define min(a,b)  ( (a<b)? a : b )

#include <pupconstants.h>
#include <pupstatus.h>
#include <eftp.h>

EfSendPckt(Efchan, buf, blen)
struct EftpChan *Efchan;		/* open eftp channel */
char *buf;				/* data buffer */
int   blen;				/* number of bytes to send */
{	/* */
	int retry;
	int inhibit;		/* INVARIANT -- MUST BE 0 or 1 */
	int rstat;
	uchar rpuptype;
	ulong rpupid;
	char msgbuf[100];
	int msgbuflen;

	blen = min(blen,EFTP_MAX_PACKET);	/* don't send too much! */

	inhibit = 0;		/* don't inhibit packet sending */

	for (retry=0; retry < Efchan->WaitTime ; retry++) {
		/* attempt to get a packet accross */

		/* the "inhibit" flag is used to avoid re-sending too
		 * quickly if we get a duplicate ACK; the problem is
		 * that an ACK for the packet we just sent may already
		 * be on its way, and we will get into a situation where
		 * every packet is sent twice if we don't watch it.
		 */
		if (!inhibit)	/* test (and clear later) inhibit */
		    pupwrite(&Efchan->pchan,EFTPDATA,Efchan->sequence,
				buf, blen);
			/* pup id is sequence number */
		inhibit = 0;
		
		/* wait for an ACK */
		rstat = pupread(&Efchan->pchan,msgbuf,&msgbuflen,
				&rpuptype, &rpupid, NULL, NULL);
		if (rstat == BADCKSUM || rstat == TIMEOUT) continue;

		/* got a packet */

		switch ((int)rpuptype) {

		case EFTPACK:
			if (rpupid == Efchan->sequence) {	/* right ack */
				Efchan->sequence++; /* incr. sequence */
				return(OK);
				}
			else {	/* got the wrong ack */
				if (rpupid > Efchan->sequence) {
					/* future packet acked ?! */
					return(EFTP_BADACK);
					}
				}
			/* other possibility is repeated ack; ignore it,
			 * but inhibit resending the packet for next
			 * timeout period - another ack may be coming.
			 */
			inhibit++;
			break;	/* effect is to repeat loop & retry */
		
		case EFTPABORT:
			EftpAbortCode = *(ushort *)msgbuf;
			movestring(&msgbuf[2],EftpErrMsg,msgbuflen-2);
			EftpErrMsg[msgbuflen-2] = 0; /* nullterm string */
			return(EFTP_ABORT);
		
		default:	/* we got the wrong packet type! */
			return(EFTP_ERROR);
			}
		}
	/* too many retries */
	return(TIMEOUT);
}